0.1 Intro

En esta segunda clase aprovecharemos para aprender una serie de herramientas sumamente útiles al momento de trabajar con datos geográficos:

  • Geocodificar direcciones
  • Cargar capas base para dar contexto
  • Realizar mapas de calor o heatmaps
  • Calcular distancias

0.2 Geocodificando direcciones

Muchas veces la información que tenemos hace referencia a un lugar en el terreno pero no tenemos un par de coordenadas para ubicar en un mapa. Por ejemplo si contamos con un listado que tiene direcciones, por ejemplo Tres Arroyos 614, que sabemos dónde está pero no tenemos un par de coordenadas que permiten ubicarla en un mapa.

Por suerte esto tiene una solución! Geocodificación es el proceso que permite transformar una dirección exacta en un par de coordenadas, permitiendo así tener un objeto geográfico con una geometría precisa.

Usar los servicios de Open Street Map, Google o Here son algunas opciones que tenemos pero hoy vamos a usar el servicio web de geocodificación del Gobierno de la Ciudad de Buenos Aires, el cual es libre y gratuito.

Hay un montón de funcionalidades que tiene, pero hoy vamos a usar 2 principales que son muy útiles: normalización y geocodificación. Es decir que en un simple paso vamos a “corregir” el campo de una dirección para pasarlo al nombre oficial y luego transformar esa dirección normalizada a un punto en el mapa!

La librería que nos facilita el uso de este servicio se llama RUMBA, la cual la instalamos con el clásico install.packages("RUMBA"), y los datos que vamos a usar son un listado de direcciones de farmacias en la Ciudad de Buenos Aires.

#install.packages("devtools")
#devtools::install_github("bitsandbricks/RUMBA")

library(RUMBA)
library(tidyverse)
library(sf)

farmacias <- read.csv("https://raw.githubusercontent.com/martoalalu/clase-geo-salud/master/data/farmacias.csv")

head(farmacias)
##   id           direccion
## 1  1      SANTANDER 5101
## 2  2   AV RIVADAVIA 8900
## 3  3 JURAMENTO y cabildo
## 4  4  AV CORRIENTES 5000
## 5  5   AV CABILDO y Pico
## 6  6   AV RIVADAVIA 6202

El dataframe tiene una columna que tiene la dirección. Qué bien! Pero no tiene lat-long… Qué mal! Podemos geolocalizarla igual! Qué bien!

Con la función mutate_USIG_geocode podemos agregar las columnas de lon y lat y así tener nuestro tan preciado par de coordenadas. Es bastante simple, en primer lugar le indicamos el dataframe (aca es farmacias) y luego le especificamos el campo que tiene la dirección entre comillas. Y listo, ya tenemos un dataframe con par de coordenadas. Magia!

farmacias_geo <- mutate_USIG_geocode(farmacias, "direccion")

head(farmacias_geo)
##   id           direccion                address_normalised       lon
## 1  1      SANTANDER 5101              SANTANDER 5101, CABA -58.47806
## 2  2   AV RIVADAVIA 8900          RIVADAVIA AV. 8900, CABA -58.48926
## 3  3 JURAMENTO y cabildo JURAMENTO AV. y CABILDO AV., CABA -58.45670
## 4  4  AV CORRIENTES 5000         CORRIENTES AV. 5000, CABA -58.43616
## 5  5   AV CABILDO y Pico          CABILDO AV. y PICO, CABA -58.47436
## 6  6   AV RIVADAVIA 6202          RIVADAVIA AV. 6202, CABA -58.45410
##         lat
## 1 -34.66620
## 2 -34.63574
## 3 -34.56204
## 4 -34.60083
## 5 -34.54076
## 6 -34.62574

Y ahora sí podemos pasarlo a objeto geográfico y luego al mapa!

farmacias_geo <- farmacias_geo %>% 
  filter(!is.na(lon), !is.na(lat)) %>% 
  st_as_sf(coords = c("lon", "lat"), crs = 4326)

farmacias_geo
## Simple feature collection with 48 features and 3 fields
## geometry type:  POINT
## dimension:      XY
## bbox:           xmin: -58.50898 ymin: -34.66739 xmax: -58.3647 ymax: -34.54076
## CRS:            EPSG:4326
## First 10 features:
##    id             direccion                  address_normalised
## 1   1        SANTANDER 5101                SANTANDER 5101, CABA
## 2   2     AV RIVADAVIA 8900            RIVADAVIA AV. 8900, CABA
## 3   3   JURAMENTO y cabildo   JURAMENTO AV. y CABILDO AV., CABA
## 4   4    AV CORRIENTES 5000           CORRIENTES AV. 5000, CABA
## 5   5     AV CABILDO y Pico            CABILDO AV. y PICO, CABA
## 6   6     AV RIVADAVIA 6202            RIVADAVIA AV. 6202, CABA
## 7   7           MORENO 2502                   MORENO 2502, CABA
## 8   8 LIBERTAD y Libertador LIBERTAD y DEL LIBERTADOR AV., CABA
## 9   9              PERU 402                      PERU 402, CABA
## 10 10         santa fe 3944             SANTA FE AV. 3944, CABA
##                       geometry
## 1   POINT (-58.47806 -34.6662)
## 2  POINT (-58.48926 -34.63574)
## 3   POINT (-58.4567 -34.56204)
## 4  POINT (-58.43616 -34.60083)
## 5  POINT (-58.47436 -34.54076)
## 6   POINT (-58.4541 -34.62574)
## 7  POINT (-58.40158 -34.61331)
## 8  POINT (-58.38284 -34.58823)
## 9  POINT (-58.37466 -34.61281)
## 10 POINT (-58.41905 -34.58314)

Genial. Ahora nuestro objeto es geográfico 100%. Por último, al mapa.

ggplot() +
  geom_sf(data=farmacias_geo)

Ok. Logramos mapear los puntos pero no tenemos una referencia clara, ni siquiere sabemos si todos están en la Ciudad de Buenos Aires. Como que el mapa está vacío…

0.3 Datos con contexto: capas base

Cuando manejamos datos geográficos el contexto es algo muy importante, tener una referencia sobre dónde están ubicados es clave ya que nos sitúa y al mismo tiempo comunica mejor. Una manera de hacer esto es agregandole una capa base, algo asi como el lienzo sobre el cual “pintamos” nuestros datos.

Para hacerlo vamos a usar las librerías ggmap y osmdata.

Básicamente lo primero que tenemos que hacer es indicarle a R cuál es el limite, el boundin gbox del mapa que queremos descargarnos. Usamos la función getbb y le decimos que es “Ciudad Autónoma de Buenos Aires” ya que es el nombre oficial. Si estuvieramos haciendo un mapa de por ejemplo Rosario le indicaríamos “Rosario, Santa Fe, Argentina”.

library(ggmap)
library(osmdata)

bbox <- getbb("Ciudad Autónoma de Buenos Aires,Argentina")

head(bbox)
##         min       max
## x -58.53145 -58.33512
## y -34.70564 -34.52655

El resultado es una matriz que tiene las X e Y mínimas y máximas que delimitan a la Ciudad de Buenos Aires. Ahora lo que tenemos que hacer es pedirle que nos tragia la capa base con get_stamenmap, la cual tiene una serie de parámetros a especificar:

  • En bboxle indicamos los límites específicos, en este caso lo tenemos guardado en un objeto asi que ponemos el nombre con el que lo guardamos (bbox).

  • En maptype le indicamos el tipo de mapa que queremos descargarnos. Hay capas base que tienen el terreno, otros solo las calles, algunos en blanco y negro. Ahora nos estamos descargando el toner-background, pero si quieren otro tipo pueden chequear la página de Stamen Maps.

  • En zoom le indicamos el nivel de detalle que queremos. A más zoom, más detalle, pero también más pesado el archivo que nos descarguemos…

#Descargamos el mapa
CABA <- get_stamenmap(bbox = bbox,
                      maptype = "terrain",zoom=12)

Luego para volver a mapear en vez de usar ggplot() vamos a usar ggmap() pero no se preocupen la sintaxis sigue siendo la misma!

Llamamos ala nueva función y entre parentesis le indicamos el nombre del objeto que tiene descargado el mapa que usaremos como capa base.

ggmap(CABA)

Perfecto! Lo bueno es que si no nos gusta este mapa podemos probar con otro muy fácilmente, por ejemplo con toner-background.

CABA <- get_stamenmap(bbox = bbox,
                      maptype = "toner-background",zoom=12)

ggmap(CABA)

Y ahora sólo resta agregar los datos como una capa más.

ggmap(CABA) +
  geom_sf(data=farmacias_geo, inherit.aes=FALSE)

Genial! Ahora sí tenemos una referencia más clara!

0.4 Más allá del choropleth

Hagamos otros tipos de mapas. Tener ubicaciones exactas, es decir objetos que son puntos, nos permiten hacer otros tipos de mapas como de calor (heatmap), de burbujas (bubblemap) o de densidad (densitymap), entre otros.

Una de las problemáticas del coronavirus es su elevada letalidad en personas mayores de 65 años, lo cual hace que los geriátricos sean focos especialmente críticos. Hagamos algunos mapas para ver cuál es su distribución en la Ciudad!

geriatricos <- read.csv("https://raw.githubusercontent.com/martoalalu/clase-geo-salud/master/data/geriatricos_caba.csv")

head(geriatricos)
##           X         Y                                     NOMBRE
## 1 -58.46980 -34.60002 RES. 12 DE OCTUBRE DE NORMA ADRIANA SOLARI
## 2 -58.41012 -34.62774                         HOGAR ENTRE AMIGOS
## 3 -58.45223 -34.55906                     CLUB RES.L FLOR DE LIS
## 4 -58.42462 -34.61437                           OMEGA III S.R.L.
## 5 -58.44122 -34.59847                               STELLA MARIS
## 6 -58.43462 -34.59418                    GER. LA CASA DE LA BOBE
##             CALLE  ALTURA             REPRES_TEC               TELEFONO
## 1   12 DE OCTUBRE    1665              ROMAGNOLI 4301-6695;155-248-7652
## 2 24 DE NOVIEMBRE    1421  GRIFFO MATIAS NICOLAS           155-339-2274
## 3    3 DE FEBRERO 2115/21 ALIMENA EDUARDO NAHUEL           154-421-9217
## 4   33 ORIENTALES   78/82         ADRIANA MUÂ¥IZ             1561554283
## 5         ACEVEDO 356/360  CUENCA GUILLERMO JUAN              4797-8032
## 6         ACEVEDO     950   CERVERA ROBERTO HUGO              4545-7331
##                                              MAIL
## 1                 gustavojromagnoli@speedy.com.ar
## 2                          mgriffo_2000@yahoo.com
## 3 nahuel@alimena.com.ar, lauraperezarias@sion.com
## 4                            aimuniz@hot.mail.com
## 5                       guillermocuenca@gmail.com
## 6                             r_cervera@yahoo.com
##                           NOM_GEO   COMUNAS       BARRIOS SUMI_ELECT
## 1              1665 12 DE OCTUBRE Comuna 15      Paternal     Edesur
## 2            1421 24 DE NOVIEMBRE  Comuna 3 San Cristobal     Edesur
## 3            2115/21 3 DE FEBRERO Comuna 13      Belgrano     Edenor
## 4 78/82 TREINTA Y TRES ORIENTALES  Comuna 5       Almagro     Edesur
## 5                 356/360 ACEVEDO Comuna 15  Villa Crespo     Edesur
## 6                     950 ACEVEDO Comuna 15  Villa Crespo     Edesur
##   POBLAC GRUP_ELECT                        SUMINISTR ID
## 1                                                     1
## 2                   CAMBIO DE REPRESENTANTE TÉCNICO  2
## 3                                                     3
## 4                                                     4
## 5                                                     5
## 6     22         NO                                   6

Según el dataframe hay 558 geriátricos en la Ciudad. Para hacer los siguientes mapas no vamos a convertir este objeto a un objeto geográfico ya que vamos a aprovechar unos parámetros de ggplot() que se pueden aplicar cualquier tipo de dataframe que tenga 2 columnas numéricas (y que por tanto pueden ubicarse en un eje cartesiano).

Vamos a empezar a hacer un geom_point() indicandole que el eje X es nuestra longitud y el eje Y nuestra latitud.

ggmap(CABA) +
    geom_point(data=geriatricos, aes(x=X, y=Y))

Nos da la sensación en zonas cómo Villa Urquiza, Flores, Caballito y Colegiales tienen concentración de geriátricos. Pero este tipo de mapa no nos impide ver con facilidad.

Hagamos un mapa de densidad. Para eso usamos el parámetro geom_bind2

ggmap(CABA)+
  geom_bin2d(data = geriatricos, aes(x=X, y=Y), bins = 30) +
  scale_fill_viridis_c()

R directamente arma grillas de igual tamaño, cuenta la cantidad de puntos que hay en cada celda y le asigna un color. Todo en uno! Esto es muy útil cuando queremos ver concentración de eventos.

Ahora probemos con un mapa que muestre la misma información pero simulando curvas de nivel.

ggmap(CABA) +
  stat_density2d(data = geriatricos, aes(x = X, y = Y, fill=stat(level)),geom="polygon")+
  scale_fill_viridis_c()

Bastante mejor! Hay una concentración muy marcada en Flores, es el pico de nuestra “montaña de geriátricos”. Con este tipo de visualización Villa Urquiza y Caballito son más “sierras”.